package com.gitee.wsl.security.encrypt.sample

import com.gitee.wsl.ext.string.binary2Ascii
import com.gitee.wsl.ext.string.toBinaryString
import com.gitee.wsl.security.encrypt.Encrypt
import com.gitee.wsl.security.encrypt.StringToStringEncrypt


object Gray :StringToStringEncrypt{
    val length: Int = 0
    val delimiter: String = " "


    override fun encrypt(src: String): String =
        src.grayEncode(length,delimiter)

    override fun decrypt(src: String): String =
        src.grayDecode(length,delimiter)

}

val Encrypt.Companion.gray get() = Gray

internal fun String.grayEncode(length: Int = 0, delimiter: String = " "): String {
    val binary = toBinaryString()
    val len = length.takeIf { it > 0 } ?: binary.length
    return binary.chunked(len).joinToString(delimiter) {
        it.foldIndexed(StringBuilder()) { index, acc, c ->
            acc.apply {
                if (index == 0) {
                    acc.append(c)
                } else {
                    acc.append((c - '0').xor(it[index - 1] - '0'))
                }
            }
        }
            .toString()
    }
}

internal fun String.grayDecode(length: Int = 0, delimiter: String = " "): String {
    val binary = replace(delimiter, "").replace("[^01]".toRegex(), "")
    val len = length.takeIf { it > 0 } ?: binary.length
    return binary
        .chunked(len)
        .joinToString("") {
            it.foldIndexed(StringBuilder()) { index, acc, c ->
                acc.apply {
                    if (index == 0) {
                        acc.append(c)
                    } else {
                        acc.append((c - '0').xor(acc.last() - '0'))
                    }
                }
            }
                .toString()
        }
        .binary2Ascii()
}
